#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <modbus.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <errno.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sqlite3.h>
#include <time.h>
#include "shmem.h"
#include "msg_queue_peer.h"

union val_t
{
    BOOL b_val;  // bool类型存储空间
    int i_val;   // 整形值存储空间
    float f_val; // 浮点值存储空间
};

struct control
{
    long Equ;        // 消息类型
    int key;         // 设备ID
    char name[32];   // 设备名称
    union val_t val; // 数据设置
    int addr;        // 线圈寄存器
    int type;        // 数据点值的类型，1：bool类型 2：int型  3：float型
};
// 消息队列

struct data32
{
    int key;
    char name[32];
    union val_t val; // 实时数据
    int type;        // 数据类型
};
typedef struct datam
{
    int key;
    char name[32];
    union val_t val; // 实时数据
    int addr;        // modbus地址
    int type;        // 数据类型
} modbus_msg;

typedef struct data
{
    struct data32 d32[10];
    struct datam dmod[10]; // Modbus结构体数组
    int arrsize;
} shmdata;
// 共享内存

void *handler(void *arg)
{
    modbus_t *ctx = (modbus_t *)arg;
    struct shm_param para;
    // 初始化共享内存
    if (shm_init(&para, "shm", sizeof(shmdata)) < 0)
    {
        perror("shm create erro\n");
        return NULL;
    }
    // 获取共享内存写的首地址
    shmdata *shmdata = (struct data *)shm_getaddr(&para);
    // 存放温湿度Co2的数据
    uint16_t dest[4];
    // 存放设备状态的数据
    uint8_t state[4];
    while (1)
    {
        // 读modbus slave温湿度Co2数据
        modbus_read_registers(ctx, 0, 6, dest);
        // 读modbus slave各个设备的状态
        modbus_read_bits(ctx, 0, 4, state);
        shmdata->dmod[0].val.f_val = modbus_get_float_dcba(dest);     // 温度
        shmdata->dmod[1].val.f_val = modbus_get_float_dcba(dest + 2); // 湿度
        shmdata->dmod[3].val.f_val = modbus_get_float_dcba(dest + 4); // Co2

        shmdata->dmod[2].val.i_val = state[0]; // 空调状态
        shmdata->dmod[4].val.i_val = state[1]; // 灯状态
        shmdata->dmod[5].val.i_val = state[2]; // 门禁状态
        shmdata->dmod[6].val.i_val = state[3]; // 蜂鸣器状态
        shmdata->arrsize = 7;                  // 总共数据的状态
    }
}
int main(int argc, char const *argv[])
{
    // 创建并初始化
    modbus_t *ctx = modbus_new_tcp(argv[1], 502);
    if (ctx == NULL)
    {
        printf("modbus_new_tcp err");
        return -1;
    }

    // 设置从机
    modbus_set_slave(ctx, 1);
    // 建立链接
    if (modbus_connect(ctx) < 0)
    {
        perror("modbus connect err");
        modbus_free(ctx);
        return -1;
    }
    printf("connect ok\n");
    // 创建线程
    pthread_t tid, tid1;
    if (pthread_create(&tid, NULL, handler, ctx) != 0)
    {
        perror("create err");
        modbus_free(ctx);
        modbus_close(ctx);
        return -1;
    }
    pthread_detach(tid);

    while (1)
    {
        // 创建关于消息队列的结构体变量
        struct control ctrl;
        // 创建消息队列
        if(msg_queue_recv("msg", &ctrl, sizeof(ctrl), 1, 0) < 0)
        {
            perror("shm create erro\n");
            return -1;
        }

        // 判对key值，是否需要修改modbus slave上设备的状态
        switch (ctrl.key)
        {
        case 103:
            // 写bool型
            modbus_write_bit(ctx, 0, ctrl.val.b_val); // 写空调状态
            break;
        case 105:
            modbus_write_bit(ctx, 1, ctrl.val.b_val); // 写灯状态
            break;
        case 106:
            modbus_write_bit(ctx, 2, ctrl.val.b_val); // 写门禁状态
            break;
        case 107:
            modbus_write_bit(ctx, 3, ctrl.val.b_val); // 写蜂鸣器状态
            break;
        default:
            break;
        }
    }

    return 0;
}
